#include "xtypes.h"
#include "xstream.h"
#include "xbuffer.h"
#include "xmemory.h"

//////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////

int_t CxRingQueue::capacity() const
{
	return m_PhySize;
}

int_t CxRingQueue::size() const
{
	int_t nHead = m_nHead;
	int_t nTail = m_nTail;

	int_t nBufferDataSize = ( nTail - nHead + m_PhySize ) % m_PhySize;
	return nBufferDataSize;
}

bool_t CxRingQueue::empty() const
{
	int_t nHead = m_nHead;
	int_t nTail = m_nTail;

	return (nHead==nTail ? TRUE:FALSE);
}


xResult CxRingQueue::push( const wildptr_t _DataPtr, int_t _Size )
{
	int_t nHead = m_nHead;
	int_t nTail = m_nTail;

	memptr_t pDataPtr = (memptr_t)_DataPtr;
	int_t nDataSize = _Size;

	int_t nBufferDataSize = ( nTail - nHead + m_PhySize ) % m_PhySize;
	int_t nRemainSize = m_PhySize - nBufferDataSize;

	if( nDataSize > nRemainSize )
	{
		return XR_FAIL;
	}

	if( nTail+nDataSize < m_PhySize )
	{
		xMemoryCopy(m_PhyPtr + nTail, pDataPtr + 0, nDataSize);
		nTail = nTail + nDataSize;
	}
	else
	{
		int_t nSizePart1 = m_PhySize - nTail;
		int_t nSizePart2 = nDataSize - nSizePart1;
		xMemoryCopy(m_PhyPtr + nTail, pDataPtr + 0, nSizePart1);
		xMemoryCopy(m_PhyPtr + 0, pDataPtr + nSizePart1, nSizePart2);
		nTail = nSizePart2;
	}

	m_nTail = nTail;
	return XR_OK;
}

xResult CxRingQueue::pop( wildptr_t _DataPtr, int_t _Size )
{
	int_t nHead = m_nHead;
	int_t nTail = m_nTail;

	memptr_t pDataPtr = (memptr_t)_DataPtr;
	int_t nDataSize = _Size;

	int_t nBufferDataSize = ( nTail - nHead + m_PhySize ) % m_PhySize;

	if( nDataSize > nBufferDataSize )
	{
		return XR_FAIL;
	}

	if( nHead+nDataSize < m_PhySize )
	{
		xMemoryCopy(pDataPtr + 0, m_PhyPtr+nHead, nDataSize);
		nHead = (nHead + nDataSize) % m_PhySize;
	}
	else
	{
		int_t nSizePart1 = m_PhySize - nHead;
		int_t nSizePart2 = nDataSize - nSizePart1;

		xMemoryCopy(pDataPtr + 0, m_PhyPtr + nHead, nSizePart1);
		xMemoryCopy(pDataPtr + nSizePart1, m_PhyPtr + 0, nSizePart2);
		nHead = nSizePart2;
	}

	m_nHead = nHead;
	return XR_OK;
}

CxRingQueue::CxRingQueue()
{
	_Init();
	_Alloc( Const_CxRingQueue_Buffer_Size_Default );
}

CxRingQueue::CxRingQueue( int_t _Size )
{
	_Init();
	_Alloc(_Size);
}

CxRingQueue::CxRingQueue( const CxRingQueue& _Ref )
{
	_Copy(_Ref);
}

CxRingQueue& CxRingQueue::operator=( const CxRingQueue& _R )
{
	_Copy(_R);
	return (*this);
}

CxRingQueue::~CxRingQueue()
{
	_Tidy();
}

void CxRingQueue::_Init()
{
	m_PhyPtr = NULL;
	m_PhySize = 0;
	m_nHead = 0;
	m_nTail = 0;
}

void CxRingQueue::_Alloc( int_t _Size )
{
	_Tidy();

	memptr_t ptr = (memptr_t)xMemoryAlloc(_Size);
	if( ptr!=NULL )
	{
		m_PhyPtr = ptr;
		m_PhySize = _Size;
		m_nHead = 0;
		m_nTail = 0;
	}
}

void CxRingQueue::_Tidy()
{
	if(m_PhyPtr != NULL)
	{
		xMemoryFree(m_PhyPtr);

		m_PhyPtr = NULL;
		m_PhySize = 0;
		m_nHead = 0;
		m_nTail = 0;
	}
}

void CxRingQueue::_Copy( const CxRingQueue& _Ref )
{
	_Tidy();

	if( _Ref.m_PhySize != 0)
	{
		_Alloc(_Ref.m_PhySize);
		xMemoryCopy(this->m_PhyPtr, _Ref.m_PhyPtr, _Ref.m_PhySize);
		this->m_nHead = _Ref.m_nHead;
		this->m_nTail = _Ref.m_nTail;
	}
}







//////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////


void CxStream::writeU64( qword_t _Data )
{
	writeUx<qword_t>(_Data);
}

void CxStream::writeU32( dword_t _Data )
{
	writeUx<dword_t>(_Data);
}

void CxStream::writeU16( word_t _Data )
{
	writeUx<word_t>(_Data);
}

void CxStream::writeU8( byte_t _Data )
{
	writeUx<byte_t>(_Data);
}

qword_t CxStream::readU64()
{
	return readUx<qword_t>();
}

dword_t CxStream::readU32()
{
	return readUx<dword_t>();
}

word_t CxStream::readU16()
{
	return readUx<word_t>();
}

byte_t CxStream::readU8()
{
	return readUx<byte_t>();
}

CxStream::~CxStream()
{
	_Tidy();
}

CxStream::CxStream()
:_Mybase()
{
	_Init();
}

CxStream::CxStream( int_t _Size )
:_Mybase(_Size)
{
	_Init();
}

void CxStream::readString( CxStringA& _Str, int_t _Len )
{
	if( _Len <= 0 )
		return;

	CxStaticBuffer tmp( _Len );
	_Myt::pop( tmp.data(), tmp.size() );
	_Str.clear();
	_Str.insert( 0, (lpcstr_t)tmp.data(), tmp.size() );

}


void CxStream::writeString( const CxStringA& _Str, int_t _Len )
{
	if( _Len <= 0 || _Len > _Str.size() )
		return;

	_Myt::push( (memptr_t)_Str.data(), _Str.size() );
}

void CxStream::readData( wildptr_t _DataPtr, int_t _Size )
{
	_Myt::pop( _DataPtr, _Size );
}


void CxStream::writeData( const wildptr_t _DataPtr, int_t _Size )
{
	_Myt::push( _DataPtr, _Size );
}


int_t CxStream::capacity() const
{
	return _Mybase::capacity();
}

int_t CxStream::size() const
{
	return _Mybase::size();
}


bool_t CxStream::empty() const
{
	return _Mybase::empty();
}

void CxStream::_Init()
{
	m_IsNeedChangeByteOrder = !xIsLittleEndian();
}

void CxStream::_Tidy()
{

}


CxStream* CxStream::Create()
{
	CxStream* _Ptr = xNewObject<CxStream>();
	if(_Ptr==NULL)
		return NULL;

	return _Ptr;
}

void CxStream::Release()
{
	xDeleteObject<CxStream>(this);
}


CxStream& CxStream::operator>>( CxStringA& _str )
{
	word_t nLen = _Myt::readU16();
	_Myt::readString(_str, nLen);
	return *this;
}

CxStream& CxStream::operator>>( uint8_t& _val )
{
	_val = _Myt::readU8();
	return *this;
}

CxStream& CxStream::operator>>( uint16_t& _val )
{
	_val = _Myt::readU16();
	return *this;
}

CxStream& CxStream::operator>>( uint32_t& _val )
{
	_val = _Myt::readU32();
	return *this;
}

CxStream& CxStream::operator>>( uint64_t& _val )
{
	_val = _Myt::readU64();
	return *this;
}

CxStream& CxStream::operator<<( const CxStringA& _str )
{
	word_t nLen = _str.length();
	_Myt::writeU16(nLen);
	_Myt::writeString(_str, nLen);
	return *this;
}

CxStream& CxStream::operator<<( const uint8_t& _val )
{
	_Myt::writeU8(_val);
	return *this;
}

CxStream& CxStream::operator<<( const uint16_t& _val )
{
	_Myt::writeU16(_val);
	return *this;
}

CxStream& CxStream::operator<<( const uint32_t& _val )
{
	_Myt::writeU32(_val);
	return *this;
}

CxStream& CxStream::operator<<( const uint64_t& _val )
{
	_Myt::writeU64(_val);
	return *this;
}


//////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////



